﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.IO;
using Aspose.Words;
using Aspose.Words.Tables;
using Aspose.Words.Drawing;
using System.Collections;
using Aspose.Words.Layout;

namespace ASPNet_User_Input_Invoice_To_PDF
{
    public partial class _Default : System.Web.UI.Page
    {
        #region Page load and events

        // page load event
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                // verify page is not post back, so we can setup default page view.
                if (!Page.IsPostBack)
                {
                    // calling this function to create default four rows when page initialy loaded.
                    PopulateProductsGrid(5);
                }
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        // adding rows in invoice products gridview.
        protected void btnAddProducts_Click(object sender, EventArgs e)
        {
            try
            {
                // varify textbox is not empty
                if (!txtAddProductRows.Text.Trim().Equals(""))
                {
                    // populating product empty rows as per user input for rows
                    PopulateProductsGrid(int.Parse(txtAddProductRows.Text.Trim()));
                }
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        // button even to generate invoice in PDF file
        protected void btnGeneratePDF_Click(object sender, EventArgs e)
        {
            try
            {
                string TargetPathFileSave = "";

                // verify file is selected by user to upload
                if (fuCompanyLogo.HasFile)
                {
                    // base directory path to upload image
                    TargetPathFileSave = Server.MapPath(GetDataDir_LogoImages());

                    // use GUID to distinct each file name
                    Guid nimgGUID = Guid.NewGuid();
                    TargetPathFileSave = TargetPathFileSave + nimgGUID.ToString().Trim() + fuCompanyLogo.FileName.Substring(fuCompanyLogo.FileName.LastIndexOf('.')).ToLower();

                    // upload file to server
                    fuCompanyLogo.PostedFile.SaveAs(TargetPathFileSave);
                }
                else
                {
                    // if no file selected then company name should be provided by user
                    if (txtCompanyName.Text.Trim().Equals(""))
                    {
                        // in case no file and company name provided then notify user and stop process
                        lblMessage.Text = "please select file to upload.";
                        return;
                    }
                }

                // generating PDF for user input using template document
                MergeWithWordTemplate(Server.MapPath(GetDataDir_Templates()), Server.MapPath(GetDataDir_OutputDocs()), TargetPathFileSave);

            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        // button event to clear form fields
        protected void btnClearForm_Click(object sender, EventArgs e)
        {
            try
            {
                // in this demo example one page by redirecting to same page will reset all fields to its initial state
                Response.Redirect("~/Default.aspx");
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        // products gridview row data bound event to populate VAT dropdown list
        protected void grdInvoiceProducts_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            try
            {
                if (e.Row.RowType == DataControlRowType.DataRow)
                {
                    // getting object of VAT dropdown list for each row
                    DropDownList ddlProductVAT = (DropDownList)e.Row.FindControl("ddlProductVAT");

                    // verify dropdown list object is not null
                    if (ddlProductVAT != null)
                    {
                        // call populate VAT dropdown list
                        PopulateVATDropdownList(ref ddlProductVAT);
                    }
                }
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        #endregion

        #region Private methods

        // adding rows in invoice products gridview
        private void PopulateProductsGrid(int addRows)
        {
            try
            {
                // Create a new DataSet and DataTable objects to be used for mail merge.
                DataSet data = new DataSet();
                DataTable productTable = new DataTable("ProductTable");

                // Add columns for the productTable table.
                productTable.Columns.Add("ProductId");
                productTable.Columns.Add("Description");
                productTable.Columns.Add("Price");
                productTable.Columns.Add("Quantity");
                productTable.Columns.Add("TotalBeforVAT");
                productTable.Columns.Add("VATPercent");
                productTable.Columns.Add("VATAmount");
                productTable.Columns.Add("TotalAmount");

                for (int indx = 1; indx <= addRows; indx++)
                {
                    // Add the temp data row to the tables for each row.
                    productTable.Rows.Add(indx, "", 0.0, 1, 0.0, 0.0, 0.0, 0.0);
                }

                // Include the tables in the DataSet.
                data.Tables.Add(productTable);

                grdInvoiceProducts.DataSource = data;
                grdInvoiceProducts.DataBind();
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        private void MergeWithWordTemplate(string templatePath, string outputPath, string imagePath)
        {
            try
            {
                Document doc = new Document(templatePath + "MailMerge Template.doc");

                // Fill the fields in the document with user data.
                DataSet data = new DataSet();
                DataTable productTable = new DataTable("Products");

                // Add columns for the productTable table.
                productTable.Columns.Add("ProductId");
                productTable.Columns.Add("ProductDescription");
                productTable.Columns.Add("Price");
                productTable.Columns.Add("Quantity");
                productTable.Columns.Add("TotalBeforVAT");
                productTable.Columns.Add("VATPercent");
                productTable.Columns.Add("VATAmount");
                productTable.Columns.Add("TotalAmount");

                decimal totalBeforeVAT = 0;
                decimal totalVATAmount = 0;
                decimal totalAmount = 0;
                decimal grandTotalAmount = 0;

                foreach (GridViewRow gr in grdInvoiceProducts.Rows)
                {
                    // find control in each gridview rows
                    System.Web.UI.WebControls.TextBox txtProductDescription = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductDescription");
                    System.Web.UI.WebControls.TextBox txtProductPrice = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductPrice");
                    System.Web.UI.WebControls.TextBox txtProductQuantity = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductQuantity");
                    DropDownList ddlProductVAT = (DropDownList)gr.FindControl("ddlProductVAT");

                    // varify the found controls should not be null
                    if (txtProductDescription != null && txtProductPrice != null && txtProductQuantity != null && ddlProductVAT != null)
                    {
                        // varify the found controls should not be empty
                        if (txtProductDescription.Text.Trim() != "" && txtProductPrice.Text.Trim() != "" && txtProductQuantity.Text.Trim() != "" && ddlProductVAT.Items.Count > 0)
                        {
                            // actual amount price X quantity
                            totalBeforeVAT = (decimal.Parse(txtProductPrice.Text.Trim()) * decimal.Parse(txtProductQuantity.Text.Trim()));

                            // VAT amount = (actual X VAT)/100
                            totalVATAmount = ((totalBeforeVAT * decimal.Parse(ddlProductVAT.SelectedItem.Value.Trim())) / 100);

                            // Total amount including VAT
                            totalAmount = totalBeforeVAT + totalVATAmount;
                            grandTotalAmount += totalAmount;

                            // Add the temp data row to the tables for each row.
                            productTable.Rows.Add(gr.Cells[0].Text, txtProductDescription.Text.Trim(), decimal.Parse(txtProductPrice.Text.Trim()), decimal.Parse(txtProductQuantity.Text.Trim()), totalBeforeVAT, decimal.Parse(ddlProductVAT.SelectedItem.Value), totalVATAmount, totalAmount);
                        }
                    }
                }

                // Include the tables in the DataSet.
                data.Tables.Add(productTable);

                // updating fix fields using simple aspose mail merge
                doc.MailMerge.Execute(
                    new string[] { "CompanyName", "CompanyAddress", "CompanyZipState", "CompanyCountry", "CustomerName", "CustomerAddress", "CustomerZipState", "CustomerCountry", "InvoiceTotalAmount", "CompanyLogo" },
                    new object[] { txtCompanyName.Text.Trim(), txtCompanyAddress.Text.Trim(), txtCompanyStateZip.Text.Trim(), txtCompanyCountry.Text.Trim(), txtCustomerName.Text.Trim(), txtCustomerAddress.Text.Trim(), txtCustomerStateZip.Text.Trim(), txtCustomerCountry.Text.Trim(), grandTotalAmount, (imagePath != "" ? File.ReadAllBytes(imagePath) : null) });

                doc.MailMerge.ExecuteWithRegions(data);

                // Saves the document to disk.
                doc.Save(outputPath + "Invoice.pdf");
                Response.Clear();
                Response.Buffer = true;
                Response.AddHeader("content-disposition", "attachment;filename=Invoice_" + DateTime.Now.Day.ToString() + "_" + DateTime.Now.Month.ToString() + "_" + DateTime.Now.Year.ToString() + "_" + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + "_" + DateTime.Now.Millisecond.ToString() + ".pdf");
                Response.Charset = "";
                Response.ContentType = "application/pdf";
                Response.Cache.SetCacheability(HttpCacheability.NoCache);

                Response.ContentType = "Application/pdf";

                //Get the physical path to the file.
                string FilePath = MapPath(GetDataDir_OutputDocs() + "Invoice.pdf");

                //Write the file directly to the HTTP content output stream.
                Response.WriteFile(FilePath);
                Response.Flush();
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
                Response.Clear();
                Response.Flush();
            }
        }

        // Verifying the control is rendered completely
        public override void VerifyRenderingInServerForm(Control control)
        {
            try
            {
                // nothing is required to do here, its for response and request objects default call in ASP.Net page cycle to use response write
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        // populate vat dropdown list
        private void PopulateVATDropdownList(ref DropDownList ddlVAT)
        {
            try
            {
                // if session already contains the list items then no need to execute loop and items
                if (Session["VATListItems"] != null)
                {
                    // extract items from session
                    ddlVAT.Items.AddRange(((ListItemCollection)Session["VATListItems"]).Cast<System.Web.UI.WebControls.ListItem>().ToArray());
                }
                else
                {
                    // creating items for VAT %age from 1 to 20 with decimal places 1 to 9, in this way we will have items like (e.g 1%, 1.1%, 1.2%.........19.9%, 20%)
                    // outer look for 1 to 20 items
                    for (int i = 0; i < 20; i++)
                    {
                        // inner loop to create decimal items 1 to 9 for each outer loop value
                        for (int j = 0; j < 10; j++)
                        {
                            // NOTE: (j == 0 ? "" : "." + j.ToString()) skip and allow to add start value
                            ddlVAT.Items.Add(new ListItem(i.ToString() + (j == 0 ? "" : "." + j.ToString()) + "%", i.ToString() + (j == 0 ? "" : "." + j.ToString())));
                        }
                    }
                    // adding last item as loops created max 19.9% item
                    ddlVAT.Items.Add(new ListItem("20%", "20"));

                    // adding list items to session
                    Session["VATListItems"] = ddlVAT.Items;
                }
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
            }
        }

        #endregion

        #region Folder Paths

        // path to merge templates folder
        private string GetDataDir_Templates()
        {
            try
            {
                // check if directory exist
                if (!System.IO.Directory.Exists(Server.MapPath("~/Templates/")))
                {
                    // create directory if missing
                    System.IO.Directory.CreateDirectory(Server.MapPath("~/Templates/"));
                }
                return "~/Templates/";
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
                throw exc;
            }
        }

        // path to logo images folder
        private string GetDataDir_LogoImages()
        {
            try
            {
                // check if directory exist
                if (!System.IO.Directory.Exists(Server.MapPath("~/UploadedImages/")))
                {
                    // create directory if missing
                    System.IO.Directory.CreateDirectory(Server.MapPath("~/UploadedImages/"));
                }
                return "~/UploadedImages/";
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
                throw exc;
            }
        }

        // path to output documents folder
        private string GetDataDir_OutputDocs()
        {
            try
            {
                // check if directory exist
                if (!System.IO.Directory.Exists(Server.MapPath("~/OutputDocs/")))
                {
                    // create directory if missing
                    System.IO.Directory.CreateDirectory(Server.MapPath("~/OutputDocs/"));
                }
                return "~/OutputDocs/";
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
                throw exc;
            }
        }

        #endregion

    }
}
